/*-
 * Copyright notice
 * 
 * (c) 2011 Christian Würtz <christian.wuertz@googlemail.com>
 * 
 * All rights reserved.
 * 
 * This file is part of the google-static-map-url-builder project. It is free
 * software: you can redistribute it and/or modify it under the terms of the 
 * GNU General Public License as published by the Free Software Foundation,
 * either version 2 of the License, or (at your option) any later version.
 * 
 * The google-static-map-url-builder is distributed in the hope that it will be
 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General 
 * Public License for more details.
 *  
 * You should have received a copy of the GNU General Public License
 * along with the google-static-map-url-builder. If not, see 
 * <http://www.gnu.org/licenses/>.
 */
package de.wuertz.map.types;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

import de.wuertz.map.enumeration.Color;
import de.wuertz.map.enumeration.MarkerSize;
import de.wuertz.map.exception.InvalidParameterException;

/**
 * A marker on a map.
 * 
 * TODO: Custom label support. Support for markers with the same style "style|pos1|pos2|...".
 * 
 * @author Christian Würtz <christian.wuertz@googlemail.com>
 */
public class Marker
{
	/**
	 * This pattern describes, which characters are allowed as labels.
	 */
	private static final Pattern LABEL_PATTERN = Pattern.compile( "[A-Z0-9]" );

	/**
	 * This pattern describes a 24-bit color in it's hexadecimal representation.
	 */
	private static final Pattern COLOR_PATTERN = Pattern.compile( "^0x?(([a-fA-F0-9]){3}){1,2}$" );

	/**
	 * (Required)
	 * 
	 * The position of this marker.
	 */
	private String position;

	/**
	 * (Optional)
	 * 
	 * The marker's size.
	 */
	private MarkerSize size;

	/**
	 * (Optional)
	 * 
	 * The marker's color.
	 */
	private String color;

	/**
	 * (Optional)
	 * 
	 * The label of the marker.
	 */
	private char label;

	/**
	 * Constructor.
	 * 
	 * @param position The position of the marker.
	 */
	public Marker( Coordinate position )
	{
		setPosition( position );
	}

	/**
	 * Constructor.
	 * 
	 * @param position The position of the marker.
	 */
	public Marker( String address )
	{
		setPosition( address );
	}

	/**
	 * Get the position of the marker.
	 * 
	 * @return The position of the marker as coordinate or address.
	 */
	public String getPosition()
	{
		return this.position;
	}

	/**
	 * (Required)
	 * 
	 * Set the position of the marker.
	 * 
	 * @param position The position of the marker.
	 */
	public void setPosition( Coordinate position )
	{
		this.position = position.toString();
	}

	/**
	 * (Required)
	 * 
	 * Set the position of the marker.
	 * 
	 * @param address An address (e.g. "Berkeley,CA" or "City Hall,New York,NY") or a coordinate in
	 *           it's string representation. If an address is passed, spaces will be escaped by plus
	 *           signs.
	 */
	public void setPosition( String address )
	{
		this.position = address.replace( " ", "+" );
	}

	/**
	 * Get the size.
	 * 
	 * @return The size.
	 */
	public MarkerSize getSize()
	{
		return this.size;
	}

	/**
	 * (Optional)
	 * 
	 * Set the size.
	 * 
	 * @param size The size to set.
	 */
	public void setSize( MarkerSize size )
	{
		this.size = size;
	}

	/**
	 * Get the color.
	 * 
	 * @return The color.
	 */
	public String getColor()
	{
		return this.color;
	}

	/**
	 * (Optional)
	 * 
	 * Set the color.
	 * 
	 * @param color The color to set.
	 */
	public void setColor( Color color )
	{
		this.color = color.toString();
	}

	/**
	 * (Optional)
	 * 
	 * Set the color.
	 * 
	 * @param color The color to set.
	 * 
	 * @throws InvalidParameterException
	 */
	public void setColor( String color ) throws InvalidParameterException
	{
		// Check whether the string contains a valid color representation.
		Matcher matcher = COLOR_PATTERN.matcher( color );
		if( matcher.matches() )
		{
			this.color = color.toString();
		}
		else
		{
			throw new InvalidParameterException(
					"The color representation is invalid. Must be in the format of \"0xF0F0F0\"" );
		}
	}

	/**
	 * Get the label.
	 * 
	 * @return The label.
	 */
	public char getLabel()
	{
		return this.label;
	}

	/**
	 * (Optional)
	 * 
	 * Set the label. Only one alphanumeric character in upper case {A-Z} or {0-9} is allowed.
	 * 
	 * Attention: A label can only be shown on a marker with medium size.
	 * 
	 * @param label The label to set.
	 * 
	 * @throws InvalidParameterException
	 */
	public void setLabel( char label ) throws InvalidParameterException
	{
		// Check whether the given label is an alphanumeric character in upper case {A-Z} or {0-9}.
		Matcher matcher = LABEL_PATTERN.matcher( Character.toString( label ) );
		if( matcher.matches() )
		{
			this.label = label;
		}
		else
		{
			throw new InvalidParameterException(
					"Only alphanumeric upper case characters ({A-Z} or {0-9}) are allowed." );
		}
	}

	/**
	 * Get the representation of this marker as it will be used in the URL to access Google's static
	 * maps API.
	 * 
	 * @return This marker's URL representation.
	 */
	public String getURLRepresentation()
	{
		// Create the builder that creates the URL representation of this marker.
		StringBuilder builder = new StringBuilder( 64 );
		builder.append( "&" );
		builder.append( "markers=" );

		// If the size is the default size, don't add it to the URL to make it shorter.
		if( this.size != null && this.size != MarkerSize.MID )
		{
			builder.append( "size:" );
			builder.append( this.size.toString() );
			builder.append( "|" );
		}

		// If specified, set the color of this marker.
		if( this.color != null )
		{
			builder.append( "color:" );
			builder.append( this.color.toString() );
			builder.append( "|" );
		}

		// If specified and the size is big enough, set the label.
		if( this.label != '\u0000' && ( this.size == null || this.size == MarkerSize.MID ) )
		{
			builder.append( "label:" );
			builder.append( this.label );
			builder.append( "|" );
		}

		// Set the position.
		builder.append( this.position );

		return builder.toString();
	}
}
